package cn.edu.stu.syllabus.oa.list;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import cn.edu.stu.syllabus.datas.RequestState;
import cn.edu.stu.syllabus.di.scope.FragmentScoped;
import cn.edu.stu.syllabus.repository.oa.OaDataRepository;
import cn.edu.stu.syllabus.repository.oa.OaSearchInfo;
import cn.edu.stu.syllabus.repository.oa.local.OaInfoEntry;
import cn.edu.stu.syllabus.repository.oaRead.OaReadRepository;
import cn.edu.stu.syllabus.utils.ExtraNameJoiner;
import cn.edu.stu.syllabus.utils.RxSchedulerUtils;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;

import static cn.edu.stu.syllabus.utils.NullPointerUtils.checkNotNull;

/**
 * Created by daidaijie on 2017/3/14.
 */

@FragmentScoped
public class OaPresenter implements OaContract.Presenter {

    private CompositeSubscription mSubscriptions;

    private final OaContract.View mView;
    private final OaDataRepository mOaDataRepository;
    private final OaReadRepository mOaReadRepository;
    private final OaSearchInfo mOaSearchInfo;

    private static final int OA_PAGE_NUM = 10;

    private List<OaInfoEntry> mOaInfoEntries;

    private int mPage;

    private static final String EXTRA_OA_INFO_ENTRY = ExtraNameJoiner.join(
            OaPresenter.class, "mOaInfoEntries"
    );

    private static final String EXTRA_PAGE = ExtraNameJoiner.join(
            OaPresenter.class, "mPage"
    );

    private static final String EXTRA_REQUEST_STATE = ExtraNameJoiner.join(
            OaPresenter.class, "mRequestState"
    );

    private int mRequestState;

    @Inject
    public OaPresenter(OaContract.View view,
                       OaDataRepository oaDataRepository,
                       OaReadRepository oaReadRepository,
                       OaSearchInfo oaSearchInfo) {
        mView = checkNotNull(view);
        mOaDataRepository = checkNotNull(oaDataRepository);
        mOaReadRepository = checkNotNull(oaReadRepository);
        mOaSearchInfo = checkNotNull(oaSearchInfo);
        mSubscriptions = new CompositeSubscription();
    }

    @Inject
    public void setupListeners() {
        mView.setPresenter(this);
    }

    @Override
    public void subscribe() {
        if (mOaInfoEntries == null) {
            if (RequestState.REQUEST_ERROR == mRequestState) {
                mView.showDataError();
            } else if (RequestState.REQUEST_EMPTY == mRequestState) {
                mView.showDataEmpty();
            } else {
                mRequestState = RequestState.REQUEST_FIRST;
                loadOaInfos();
            }
        } else {
            mView.setOaInfoList(mOaInfoEntries);
            if (RequestState.REQUEST_ERROR == mRequestState) {
                mView.showLoadingFail();
            } else if (RequestState.REQUEST_EMPTY == mRequestState) {
                mView.showLoadingEnd();
            }
        }
    }

    @Override
    public void unsubscribe() {
        mSubscriptions.unsubscribe();
    }

    @Override
    public void loadOaInfos() {

        if (RequestState.isFirst(mRequestState)) {
            mPage = 0;
        }

        Subscription subscription = mOaDataRepository.getOaInfoEntries(mOaSearchInfo, mPage, mPage + OA_PAGE_NUM)
                .observeOn(Schedulers.io())
                .doOnNext(new Action1<List<OaInfoEntry>>() {
                    @Override
                    public void call(List<OaInfoEntry> oaInfoEntries) {
                        for (OaInfoEntry oaInfoEntry : oaInfoEntries) {
                            oaInfoEntry.setRead(mOaReadRepository.isRead(oaInfoEntry.getMRemoteId()));
                        }
                    }
                })
                .compose(RxSchedulerUtils.<List<OaInfoEntry>>io2mainSchedulersTransformer())
                .subscribe(new Subscriber<List<OaInfoEntry>>() {
                    @Override
                    public void onStart() {
                        if (RequestState.isFirst(mRequestState)) {
                            mView.showRefreshing(true);
                            mView.setRecyclerViewEnable(false);
                        }
                    }

                    @Override
                    public void onCompleted() {
                        mView.setRecyclerViewEnable(true);
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (RequestState.isFirst(mRequestState)) {
                            if (mOaDataRepository.isSourceEmpty(e)) {
                                mRequestState = RequestState.REQUEST_EMPTY;
                                mView.showDataEmpty();
                            } else {
                                mRequestState = RequestState.REQUEST_ERROR;
                                mView.showDataError();
                            }
                            mView.showRefreshing(false);
                        } else {
                            if (mOaDataRepository.isSourceEmpty(e)) {
                                mRequestState = RequestState.REQUEST_EMPTY;
                                mView.showLoadingEnd();
                            } else {
                                mRequestState = RequestState.REQUEST_ERROR;
                                mView.showLoadingFail();
                            }
                        }
                        mView.setRecyclerViewEnable(true);
                    }

                    @Override
                    public void onNext(List<OaInfoEntry> oaInfoEntries) {
                        if (oaInfoEntries != null) {
                            if (RequestState.isFirst(mRequestState)) {
                                mOaInfoEntries = oaInfoEntries;
                                mView.setOaInfoList(oaInfoEntries);
                                mView.moveToTop();
                                mView.showRefreshing(false);
                            } else {
                                mView.appendOaInfoList(oaInfoEntries);
                            }
                            mPage += OA_PAGE_NUM;
                            mRequestState = RequestState.REQUEST_SUCCESS;
                        }
                    }
                });

        mSubscriptions.add(subscription);
    }

    @Override
    public void resetRefreshing() {
        mRequestState = RequestState.REQUEST_FIRST;
    }

    @Override
    public void markIsRead(OaInfoEntry oaInfoEntry, int position) {
        mOaReadRepository.setRead(oaInfoEntry.getMRemoteId());
        oaInfoEntry.setRead(true);
        mView.updateItem(position);
    }

    @Override
    public void clearAllRead() {
        mOaReadRepository.clearAllRead();
        mView.updateAllNotRead();
    }

    @Override
    public Map<String, Object> getStoreData() {
        Map<String, Object> storeData = new HashMap<>();
        storeData.put(EXTRA_OA_INFO_ENTRY, mOaInfoEntries);
        storeData.put(EXTRA_PAGE, mPage);
        storeData.put(EXTRA_REQUEST_STATE, mRequestState);
        return storeData;
    }

    @Override
    public void restoreData(Map<String, Object> storeData) {
        mOaInfoEntries = (List<OaInfoEntry>) storeData.get(EXTRA_OA_INFO_ENTRY);
        mPage = (int) storeData.get(EXTRA_PAGE);
        mRequestState = (int) storeData.get(EXTRA_REQUEST_STATE);
    }

}
